home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Misc Servers / Zope.exe / CPERSISTENCE.C < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  22.9 KB  |  843 lines

  1. /*****************************************************************************
  2.   
  3.   Zope Public License (ZPL) Version 1.0
  4.   -------------------------------------
  5.   
  6.   Copyright (c) Digital Creations.  All rights reserved.
  7.   
  8.   This license has been certified as Open Source(tm).
  9.   
  10.   Redistribution and use in source and binary forms, with or without
  11.   modification, are permitted provided that the following conditions are
  12.   met:
  13.   
  14.   1. Redistributions in source code must retain the above copyright
  15.      notice, this list of conditions, and the following disclaimer.
  16.   
  17.   2. Redistributions in binary form must reproduce the above copyright
  18.      notice, this list of conditions, and the following disclaimer in
  19.      the documentation and/or other materials provided with the
  20.      distribution.
  21.   
  22.   3. Digital Creations requests that attribution be given to Zope
  23.      in any manner possible. Zope includes a "Powered by Zope"
  24.      button that is installed by default. While it is not a license
  25.      violation to remove this button, it is requested that the
  26.      attribution remain. A significant investment has been put
  27.      into Zope, and this effort will continue if the Zope community
  28.      continues to grow. This is one way to assure that growth.
  29.   
  30.   4. All advertising materials and documentation mentioning
  31.      features derived from or use of this software must display
  32.      the following acknowledgement:
  33.   
  34.        "This product includes software developed by Digital Creations
  35.        for use in the Z Object Publishing Environment
  36.        (http://www.zope.org/)."
  37.   
  38.      In the event that the product being advertised includes an
  39.      intact Zope distribution (with copyright and license included)
  40.      then this clause is waived.
  41.   
  42.   5. Names associated with Zope or Digital Creations must not be used to
  43.      endorse or promote products derived from this software without
  44.      prior written permission from Digital Creations.
  45.   
  46.   6. Modified redistributions of any form whatsoever must retain
  47.      the following acknowledgment:
  48.   
  49.        "This product includes software developed by Digital Creations
  50.        for use in the Z Object Publishing Environment
  51.        (http://www.zope.org/)."
  52.   
  53.      Intact (re-)distributions of any official Zope release do not
  54.      require an external acknowledgement.
  55.   
  56.   7. Modifications are encouraged but must be packaged separately as
  57.      patches to official Zope releases.  Distributions that do not
  58.      clearly separate the patches from the original work must be clearly
  59.      labeled as unofficial distributions.  Modifications which do not
  60.      carry the name Zope may be packaged in any form, as long as they
  61.      conform to all of the clauses above.
  62.   
  63.   
  64.   Disclaimer
  65.   
  66.     THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
  67.     EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  68.     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  69.     PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
  70.     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  71.     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  72.     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  73.     USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  74.     ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  75.     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  76.     OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  77.     SUCH DAMAGE.
  78.   
  79.   
  80.   This software consists of contributions made by Digital Creations and
  81.   many individuals on behalf of Digital Creations.  Specific
  82.   attributions are listed in the accompanying credits file.
  83.   
  84.  ****************************************************************************/
  85. static char *what_string = "$Id: cPersistence.c,v 1.38.10.1 2000/06/23 17:07:59 brian Exp $";
  86.  
  87. #include <string.h>
  88. #include "cPersistence.h"
  89.  
  90. #define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
  91. #define UNLESS(E) if(!(E))
  92. #define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V)
  93. #define OBJECT(V) ((PyObject*)(V))
  94.  
  95. static PyObject *py_keys, *py_setstate, *py___dict__, *py_timeTime;
  96. static PyObject *py__p_changed, *py__p_deactivate;
  97. static PyObject *py___getattr__, *py___setattr__, *py___delattr__;
  98.  
  99. static PyObject *TimeStamp;
  100.  
  101. #ifdef DEBUG_LOG
  102. static PyObject *debug_log=0;
  103. static int idebug_log=0;
  104.  
  105. static void *
  106. call_debug(char *event, cPersistentObject *self)
  107. {
  108.   PyObject *r;
  109.  
  110.   /*
  111.   printf("%s %p\n",event,self->ob_type->tp_name);
  112.   */
  113.   r=PyObject_CallFunction(debug_log,"s(sOi)",event,
  114.               self->ob_type->tp_name, self->oid,
  115.               self->state);
  116.   Py_XDECREF(r);
  117. }
  118. #endif
  119.  
  120. static void
  121. init_strings()
  122. {
  123. #define INIT_STRING(S) py_ ## S = PyString_FromString(#S)
  124.   INIT_STRING(keys);
  125.   INIT_STRING(setstate);
  126.   INIT_STRING(timeTime);
  127.   INIT_STRING(__dict__);
  128.   INIT_STRING(_p_changed);
  129.   INIT_STRING(_p_deactivate);
  130.   INIT_STRING(__getattr__);
  131.   INIT_STRING(__setattr__);
  132.   INIT_STRING(__delattr__);
  133. #undef INIT_STRING
  134. }
  135.  
  136. static PyObject *
  137. callmethod(PyObject *self, PyObject *name)
  138. {
  139.   if(self=PyObject_GetAttr(self,name))
  140.     ASSIGN(self,PyObject_CallObject(self,NULL));
  141.   return self;
  142. }
  143.  
  144. static PyObject *
  145. callmethod1(PyObject *self, PyObject *name, PyObject *arg)
  146. {
  147.   if((self=PyObject_GetAttr(self,name)) && (name=PyTuple_New(1)))
  148.     {
  149.       PyTuple_SET_ITEM(name, 0, arg);
  150.       ASSIGN(self,PyObject_CallObject(self,name));
  151.       PyTuple_SET_ITEM(name, 0, NULL);
  152.       Py_DECREF(name);
  153.     }
  154.   return self;
  155. }
  156.  
  157. static PyObject *
  158. callmethod2(PyObject *self, PyObject *name, PyObject *arg, PyObject *arg2)
  159. {
  160.   if((self=PyObject_GetAttr(self,name)) && (name=PyTuple_New(2)))
  161.     {
  162.       PyTuple_SET_ITEM(name, 0, arg);
  163.       PyTuple_SET_ITEM(name, 1, arg2);
  164.       ASSIGN(self,PyObject_CallObject(self,name));
  165.       PyTuple_SET_ITEM(name, 0, NULL);
  166.       PyTuple_SET_ITEM(name, 1, NULL);
  167.       Py_DECREF(name);
  168.     }
  169.   return self;
  170. }
  171.  
  172. static PyObject *
  173. callmethod3(PyObject *self, PyObject *name,
  174.         PyObject *arg, PyObject *arg2, PyObject *arg3)
  175. {
  176.   if((self=PyObject_GetAttr(self,name)) && (name=PyTuple_New(3)))
  177.     {
  178.       PyTuple_SET_ITEM(name, 0, arg);
  179.       PyTuple_SET_ITEM(name, 1, arg2);
  180.       PyTuple_SET_ITEM(name, 2, arg3);
  181.       ASSIGN(self,PyObject_CallObject(self,name));
  182.       PyTuple_SET_ITEM(name, 0, NULL);
  183.       PyTuple_SET_ITEM(name, 1, NULL);
  184.       PyTuple_SET_ITEM(name, 2, NULL);
  185.       Py_DECREF(name);
  186.     }
  187.   return self;
  188. }
  189.  
  190. #define UPDATE_STATE_IF_NECESSARY(self, ER)                      \
  191. if(self->state < 0 && self->jar)                                 \
  192. {                                 \
  193.   PyObject *r;                             \
  194.                                        \
  195.   self->state=cPersistent_CHANGED_STATE;                      \
  196.   UNLESS(r=callmethod1(self->jar,py_setstate,(PyObject*)self))   \
  197.     {                                                            \
  198.       self->state=cPersistent_GHOST_STATE;                       \
  199.       return ER;                                                 \
  200.     }                                 \
  201.   self->state=cPersistent_UPTODATE_STATE;             \
  202.   Py_DECREF(r);                             \
  203. }
  204.  
  205.  
  206. static PyObject *
  207. #ifdef HAVE_STDARG_PROTOTYPES
  208. /* VARARGS 2 */
  209. PyString_BuildFormat(char *stringformat, char *format, ...)
  210. #else
  211. /* VARARGS */
  212. PyString_BuildFormat(va_alist) va_dcl
  213. #endif
  214. {
  215.   va_list va;
  216.   PyObject *args=0, *retval=0, *v=0;
  217. #ifdef HAVE_STDARG_PROTOTYPES
  218.   va_start(va, format);
  219. #else
  220.   PyObject *ErrType;
  221.   char *stringformat, *format;
  222.   va_start(va);
  223.   ErrType = va_arg(va, PyObject *);
  224.   stringformat   = va_arg(va, char *);
  225.   format   = va_arg(va, char *);
  226. #endif
  227.   
  228.   args = Py_VaBuildValue(format, va);
  229.   va_end(va);
  230.   if(! args) return NULL;
  231.   if(!(retval=PyString_FromString(stringformat))) return NULL;
  232.  
  233.   v=PyString_Format(retval, args);
  234.   Py_DECREF(retval);
  235.   Py_DECREF(args);
  236.   return v;
  237. }
  238.  
  239. /****************************************************************************/
  240.  
  241. staticforward PyExtensionClass Pertype;
  242. staticforward PyExtensionClass TPertype;
  243.  
  244. static int
  245. changed(cPersistentObject *self)
  246. {
  247.   static PyObject *builtins=0, *get_transaction=0, *py_register=0;
  248.   PyObject *T;
  249.   
  250.   if ((self->state == cPersistent_UPTODATE_STATE ||
  251.        self->state == cPersistent_STICKY_STATE)
  252.        && self->jar)
  253.     {
  254.       UNLESS (get_transaction)
  255.     {
  256.       UNLESS (py_register=PyString_FromString("register")) return -1;
  257.       UNLESS (T=PyImport_ImportModule("__main__")) return -1;
  258.       ASSIGN(T,PyObject_GetAttrString(T,"__builtins__"));
  259.       UNLESS (T) return -1;
  260.       builtins=T;
  261.       UNLESS (get_transaction=PyObject_GetAttrString(builtins,
  262.                              "get_transaction"))
  263.         PyErr_Clear();
  264.     }
  265.       if (get_transaction)
  266.     {    
  267.       UNLESS (T=PyObject_CallObject(get_transaction,NULL)) return -1;
  268.       ASSIGN(T,PyObject_GetAttr(T,py_register));
  269.       UNLESS (T) return -1;
  270.       ASSIGN(T, PyObject_CallFunction(T,"O",self));
  271.       if (T) Py_DECREF(T);
  272.       else return -1;
  273.     }
  274.  
  275.       self->state=cPersistent_CHANGED_STATE;
  276.     }
  277.  
  278.   return 0;
  279. }
  280.  
  281. static PyObject *
  282. Per___changed__(cPersistentObject *self, PyObject *args)
  283. {
  284.   PyObject *v=0;
  285.  
  286.   if (args && ! PyArg_ParseTuple(args, "|O",&v)) return NULL;
  287.   if (! v) return PyObject_GetAttr(OBJECT(self), py__p_changed);
  288.  
  289.   if (PyObject_IsTrue(v)) 
  290.     {
  291.       if (changed(self) < 0) return NULL;
  292.     }
  293.   else if (self->state >= 0) self->state=cPersistent_UPTODATE_STATE;
  294.  
  295.   Py_INCREF(Py_None);
  296.   return Py_None;
  297. }
  298.  
  299. static PyObject *
  300. Per__p_deactivate(cPersistentObject *self, PyObject *args)
  301. {
  302.   PyObject *init=0, *dict;
  303.  
  304. #ifdef DEBUG_LOG
  305.   if (idebug_log < 0) call_debug("reinit",self);
  306. #endif
  307.  
  308.   if (args && ! PyArg_ParseTuple(args,"")) return NULL;
  309.  
  310.   if (self->state==cPersistent_UPTODATE_STATE && self->jar &&
  311.       HasInstDict(self) && (dict=INSTANCE_DICT(self)))
  312.     {
  313.       PyDict_Clear(dict);
  314.       /* Note that we need to set to ghost state unless we are 
  315.      called directly. Methods that override this need to
  316.          do the same! */
  317.       self->state=cPersistent_GHOST_STATE;
  318.     }
  319.  
  320.   Py_INCREF(Py_None);
  321.   return Py_None;
  322. }
  323.  
  324. /* Load the object's state if necessary and become sticky */
  325. static int
  326. Per_setstate(cPersistentObject *self)
  327. {
  328.   UPDATE_STATE_IF_NECESSARY(self, -1);
  329.   self->state=cPersistent_STICKY_STATE;
  330.   return 0;
  331. }
  332.  
  333. static PyObject *
  334. Per__getstate__(self,args)
  335.      cPersistentObject *self;
  336.      PyObject *args;
  337. {
  338.   PyObject *__dict__, *d=0;
  339.  
  340.   UNLESS(PyArg_ParseTuple(args, "")) return NULL;
  341.  
  342. #ifdef DEBUG_LOG
  343.   if(idebug_log < 0) call_debug("get",self);
  344. #endif
  345.  
  346.   UPDATE_STATE_IF_NECESSARY(self, NULL);
  347.  
  348.   if(HasInstDict(self) && (__dict__=INSTANCE_DICT(self)))
  349.     {
  350.       PyObject *k, *v;
  351.       int pos;
  352.       char *ck;
  353.       
  354.       for(pos=0; PyDict_Next(__dict__, &pos, &k, &v); )
  355.     {
  356.       if(PyString_Check(k) && (ck=PyString_AsString(k)) &&
  357.          (*ck=='_' && ck[1]=='v' && ck[2]=='_'))
  358.         {
  359.           UNLESS(d=PyDict_New()) goto err;
  360.           for(pos=0; PyDict_Next(__dict__, &pos, &k, &v); )
  361.         UNLESS(PyString_Check(k) && (ck=PyString_AsString(k)) &&
  362.                (*ck=='_' && ck[1]=='v' && ck[2]=='_'))
  363.           if(PyDict_SetItem(d,k,v) < 0) goto err;
  364.           return d;
  365.         }
  366.     }
  367.     }
  368.   else
  369.     __dict__=Py_None;
  370.  
  371.   Py_INCREF(__dict__);
  372.   return __dict__;
  373.  
  374. err:
  375.   Py_DECREF(__dict__);
  376.   Py_XDECREF(d);
  377.   return NULL;
  378. }  
  379.  
  380. static PyObject *
  381. Per__setstate__(self,args)
  382.      cPersistentObject *self;
  383.      PyObject *args;
  384. {
  385.   PyObject *__dict__, *v, *keys=0, *key=0, *e=0;
  386.   int l, i;
  387.  
  388.   if(HasInstDict(self))
  389.     {
  390.  
  391.        UNLESS(PyArg_ParseTuple(args, "O", &v)) return NULL;
  392. #ifdef DEBUG_LOG
  393.        if(idebug_log < 0) call_debug("set",self);
  394. #endif
  395.        if(v!=Py_None)
  396.      {
  397.        __dict__=INSTANCE_DICT(self);
  398.        
  399.        if(PyDict_Check(v))
  400.          {
  401.            for(i=0; PyDict_Next(v,&i,&key,&e);)
  402.          if(PyObject_SetItem(__dict__,key,e) < 0)
  403.            return NULL;
  404.          }
  405.        else
  406.          {
  407.            UNLESS(keys=callmethod(v,py_keys)) goto err;
  408.            UNLESS(-1 != (l=PyObject_Length(keys))) goto err;
  409.            
  410.            for(i=0; i < l; i++)
  411.          {
  412.            UNLESS_ASSIGN(key,PySequence_GetItem(keys,i)) goto err;
  413.            UNLESS_ASSIGN(e,PyObject_GetItem(v,key)) goto err;
  414.            UNLESS(-1 != PyObject_SetItem(__dict__,key,e)) goto err;
  415.          }
  416.            
  417.            Py_XDECREF(key);
  418.            Py_XDECREF(e);
  419.            Py_DECREF(keys);
  420.          }
  421.      }
  422.     }
  423.   Py_INCREF(Py_None);
  424.   return Py_None;
  425. err:
  426.   Py_XDECREF(key);
  427.   Py_XDECREF(e);
  428.   Py_XDECREF(keys);
  429.   return NULL;
  430. }  
  431.  
  432.  
  433. static struct PyMethodDef Per_methods[] = {
  434.   {"__changed__",    (PyCFunction)Per___changed__,    METH_VARARGS,
  435.    "DEPRECATED: use self._p_changed=1"},
  436.   {"_p_deactivate",    (PyCFunction)Per__p_deactivate,    METH_VARARGS,
  437.    "_p_deactivate(oid) -- Deactivate the object"},
  438.   {"__getstate__",    (PyCFunction)Per__getstate__,    METH_VARARGS,
  439.    "__getstate__() -- Return the state of the object" },
  440.   {"__setstate__",    (PyCFunction)Per__setstate__,    METH_VARARGS,
  441.    "__setstate__(v) -- Restore the saved state of the object from v" },
  442.   
  443.   {NULL,        NULL}        /* sentinel */
  444. };
  445.  
  446. /* ---------- */
  447.  
  448. static void
  449. Per_dealloc(self)
  450.     cPersistentObject *self;
  451. {
  452. #ifdef DEBUG_LOG
  453.   if(idebug_log < 0) call_debug("del",self);
  454. #endif
  455.   Py_XDECREF(self->jar);
  456.   Py_XDECREF(self->oid);
  457.   Py_DECREF(self->ob_type);
  458.   PyMem_DEL(self);
  459. }
  460.  
  461. static PyObject *
  462. orNothing(PyObject *v)
  463. {
  464.   if (! v) v=Py_None;
  465.   Py_INCREF(v);
  466.   return v;
  467. }
  468.  
  469. static PyObject *
  470. Per_getattr(cPersistentObject *self, PyObject *oname, char *name,
  471.      PyObject *(*getattrf)(PyObject *, PyObject*))
  472. {
  473.   char *n=name;
  474.  
  475.   if(n && *n++=='_')
  476.     if(*n++=='p' && *n++=='_')
  477.       {
  478.     switch(*n++)
  479.       {
  480.       case 'o':
  481.         if(*n++=='i' && *n++=='d' && ! *n) return orNothing(self->oid);
  482.         break;
  483.       case 'j':
  484.         if(*n++=='a' && *n++=='r' && ! *n) return orNothing(self->jar);
  485.         break;
  486.       case 'c':
  487.         if(strcmp(n,"hanged")==0)
  488.           {
  489.         if(self->state < 0)
  490.           {
  491.             Py_INCREF(Py_None);
  492.             return Py_None;
  493.           }
  494.         return PyInt_FromLong(self->state ==
  495.                       cPersistent_CHANGED_STATE);
  496.           }
  497.         break;
  498.       case 's':
  499.         if(strcmp(n,"erial")==0)
  500.           return PyString_FromStringAndSize(self->serial, 8);
  501.         if(strcmp(n,"elf")==0) 
  502.           return orNothing(OBJECT(self));
  503.         break;
  504.       case 'm':
  505.         if(strcmp(n,"time")==0)
  506.           {
  507.         UPDATE_STATE_IF_NECESSARY(self, NULL);
  508.  
  509.         self->atime=((long)(time(NULL)/3))%65536;
  510.  
  511.         if (self->serial[7]=='\0' && self->serial[6]=='\0' &&
  512.             self->serial[5]=='\0' && self->serial[4]=='\0' &&
  513.             self->serial[3]=='\0' && self->serial[2]=='\0' &&
  514.             self->serial[1]=='\0' && self->serial[0]=='\0')
  515.           {
  516.             Py_INCREF(Py_None);
  517.             return Py_None;
  518.           }
  519.         
  520.         oname=PyString_FromStringAndSize(self->serial, 8);
  521.         if (! oname) return oname;
  522.  
  523.         ASSIGN(oname, PyObject_CallFunction(TimeStamp, "O", oname));
  524.         if (! oname) return oname;
  525.         ASSIGN(oname, PyObject_GetAttr(oname, py_timeTime));
  526.         if (! oname) return oname;
  527.         ASSIGN(oname, PyObject_CallObject(oname, NULL));
  528.         return oname;
  529.           }
  530.         break;
  531.       }
  532.  
  533.     return getattrf((PyObject *)self, oname);
  534.       }
  535.   if(! (name && *name++=='_' && *name++=='_' &&
  536.     (strcmp(name,"dict__")==0 || strcmp(name,"class__")==0
  537.      || strcmp(name, "of__")==0)))
  538.     {
  539.       UPDATE_STATE_IF_NECESSARY(self, NULL);
  540.  
  541.       self->atime=((long)(time(NULL)/3))%65536;
  542.     }
  543.  
  544.   return getattrf((PyObject *)self, oname);
  545. }
  546.  
  547. static PyObject*
  548. Per_getattro(cPersistentObject *self, PyObject *name)
  549. {
  550.   char *s=NULL;
  551.   PyObject *r;
  552.  
  553.   if (PyString_Check(name))
  554.     UNLESS(s=PyString_AsString(name)) return NULL;
  555.  
  556.   r = Per_getattr(self, name, s, PyExtensionClassCAPI->getattro);
  557.   if (! r && self->state != cPersistent_GHOST_STATE &&
  558.       (((PyExtensionClass*)(self->ob_type))->class_flags 
  559.        & EXTENSIONCLASS_USERGETATTR_FLAG)
  560.       )
  561.     {
  562.       PyErr_Clear();
  563.       r=PyObject_GetAttr(OBJECT(self), py___getattr__);
  564.       if (r) 
  565.     {
  566.       ASSIGN(r, PyObject_CallFunction(r, "O", name));
  567.     }
  568.       else PyErr_SetObject(PyExc_AttributeError, name);
  569.     }
  570.  
  571.   return r;  
  572. }
  573.  
  574. static int 
  575. bad_delattr()
  576. {
  577.   PyErr_SetString(PyExc_AttributeError,
  578.           "delete undeletable attribute");
  579.   return -1;
  580. }
  581.  
  582. static int
  583. _setattro(cPersistentObject *self, PyObject *oname, PyObject *v,
  584.          int (*setattrf)(PyObject *, PyObject*, PyObject*))
  585. {
  586.   char *name="";
  587.  
  588.   UNLESS(oname) return -1;
  589.   if(PyString_Check(oname)) UNLESS(name=PyString_AsString(oname)) return -1;
  590.     
  591.   if(*name=='_' && name[1]=='p' && name[2]=='_')
  592.     {
  593.       if(name[3]=='o' && name[4]=='i' && name[5]=='d' && ! name[6])
  594.     {
  595.       Py_XINCREF(v);
  596.       ASSIGN(self->oid, v);
  597.       return 0;
  598.     }
  599.       if(name[3]=='j' && name[4]=='a' && name[5]=='r' && ! name[6])
  600.     {
  601.       Py_XINCREF(v);
  602.       ASSIGN(self->jar, v);
  603.       return 0;
  604.     }
  605.       if(name[3]=='s' && strcmp(name+4,"erial")==0)
  606.     {
  607.       if (v)
  608.         {
  609.           if (PyString_Check(v) && PyString_Size(v)==8)
  610.         memcpy(self->serial, PyString_AS_STRING(v), 8);
  611.           else
  612.         {
  613.           PyErr_SetString(PyExc_ValueError,
  614.                   "_p_serial must be an 8-character string");
  615.           return -1;
  616.         }
  617.         }
  618.       else
  619.         memset(self->serial, 0, 8);
  620.       return 0;
  621.     }
  622.       if(name[3]=='c' && strcmp(name+4,"hanged")==0) 
  623.     {
  624.       if (! v)
  625.         {
  626.           /* delatter is used to invalidate the object
  627.              *even* if it has changed.
  628.            */
  629.           if (self->state != cPersistent_GHOST_STATE)
  630.         self->state = cPersistent_UPTODATE_STATE;
  631.           v=Py_None;
  632.         }
  633.       if (v==Py_None)
  634.         {
  635.           v=PyObject_GetAttr(OBJECT(self), py__p_deactivate);
  636.           if (v) ASSIGN(v, PyObject_CallObject(v, NULL));
  637.           if (v) Py_DECREF(v);
  638.           self->state=cPersistent_GHOST_STATE;
  639.           return 0;
  640.         }
  641.       if (PyObject_IsTrue(v)) return changed(self);
  642.       if (self->state >= 0) self->state=cPersistent_UPTODATE_STATE;
  643.       return 0;
  644.     }
  645.     }
  646.   else
  647.     {
  648.       UPDATE_STATE_IF_NECESSARY(self, -1);
  649.       
  650.       /* Record access times */
  651.       self->atime=((long)(time(NULL)/3))%65536;
  652.  
  653.       if((! (*name=='_' && name[1]=='v' && name[2]=='_'))
  654.      && (self->state != cPersistent_CHANGED_STATE && self->jar)
  655.      && setattrf
  656.      )
  657.     if(changed(self) < 0) return -1;
  658.     }
  659.  
  660.   if (setattrf)
  661.     return setattrf((PyObject*)self,oname,v);
  662.   
  663.   return 1;            /* Ready for user setattr */
  664. }
  665.  
  666. static int
  667. Per_setattro(cPersistentObject *self, PyObject *oname, PyObject *v)
  668. {
  669.   int r;
  670.   PyObject *m;
  671.  
  672.   if (v && (((PyExtensionClass*)self->ob_type)->class_flags 
  673.         & EXTENSIONCLASS_USERSETATTR_FLAG)
  674.       )
  675.     {
  676.       r=_setattro(self,oname, v, NULL);
  677.       if (r < 1) return r;
  678.  
  679.       m=PyObject_GetAttr(OBJECT(self), py___setattr__);
  680.       if (m) 
  681.     {
  682.       ASSIGN(m, PyObject_CallFunction(m, "OO", oname, v));
  683.     }
  684.       else PyErr_SetObject(PyExc_AttributeError, oname);
  685.     }
  686.   else if (!v && (((PyExtensionClass*)self->ob_type)->class_flags 
  687.           & EXTENSIONCLASS_USERDELATTR_FLAG)
  688.        )
  689.     {
  690.       r=_setattro(self,oname, v, NULL);
  691.       if (r < 1) return r;
  692.  
  693.       m=PyObject_GetAttr(OBJECT(self), py___delattr__);
  694.       if (m) 
  695.       {
  696.     ASSIGN(m, PyObject_CallFunction(m, "O", oname));
  697.       }
  698.       else PyErr_SetObject(PyExc_AttributeError, oname);
  699.     }
  700.   else
  701.     return _setattro(self,oname, v, PyExtensionClassCAPI->setattro);
  702.  
  703.   if (m) 
  704.     {
  705.       Py_DECREF(m);
  706.       return 0;
  707.     }
  708.   
  709.   return -1;
  710. }
  711.  
  712. static PyExtensionClass Pertype = {
  713.     PyObject_HEAD_INIT(NULL)
  714.     0,                /*ob_size*/
  715.     "Persistent",            /*tp_name*/
  716.     sizeof(cPersistentObject),    /*tp_basicsize*/
  717.     0,                /*tp_itemsize*/
  718.     /* methods */
  719.     (destructor)Per_dealloc,    /*tp_dealloc*/
  720.     (printfunc)0,            /*tp_print*/
  721.     (getattrfunc)0,            /*tp_getattr*/
  722.     (setattrfunc)0,                   /*tp_setattr*/
  723.     (cmpfunc)0,            /*tp_compare*/
  724.     (reprfunc)0,            /*tp_repr*/
  725.     0,                /*tp_as_number*/
  726.     0,                /*tp_as_sequence*/
  727.     0,                /*tp_as_mapping*/
  728.     (hashfunc)0,            /*tp_hash*/
  729.     (ternaryfunc)0,            /*tp_call*/
  730.     (reprfunc)0,            /*tp_str*/
  731.     (getattrofunc)Per_getattro,    /*tp_getattr with object key*/
  732.     (setattrofunc)Per_setattro,    /*tp_setattr with object key*/
  733.     /* Space for future expansion */
  734.     0L,0L,"",
  735.     METHOD_CHAIN(Per_methods),
  736.     PERSISTENCE_FLAGS,
  737. };
  738.  
  739. static PyExtensionClass Overridable = {
  740.     PyObject_HEAD_INIT(NULL)
  741.     0,                /*ob_size*/
  742.     "Persistent",            /*tp_name*/
  743.     sizeof(cPersistentObject),    /*tp_basicsize*/
  744.     0,                /*tp_itemsize*/
  745.     /* methods */
  746.     (destructor)Per_dealloc,    /*tp_dealloc*/
  747.     (printfunc)0,            /*tp_print*/
  748.     (getattrfunc)0,            /*tp_getattr*/
  749.     (setattrfunc)0,                   /*tp_setattr*/
  750.     (cmpfunc)0,            /*tp_compare*/
  751.     (reprfunc)0,            /*tp_repr*/
  752.     0,                /*tp_as_number*/
  753.     0,                /*tp_as_sequence*/
  754.     0,                /*tp_as_mapping*/
  755.     (hashfunc)0,            /*tp_hash*/
  756.     (ternaryfunc)0,            /*tp_call*/
  757.     (reprfunc)0,            /*tp_str*/
  758.     (getattrofunc)Per_getattro,    /*tp_getattr with object key*/
  759.     (setattrofunc)Per_setattro,    /*tp_setattr with object key*/
  760.     /* Space for future expansion */
  761.     0L,0L,"",
  762.     METHOD_CHAIN(Per_methods),
  763.     EXTENSIONCLASS_BASICNEW_FLAG | PERSISTENT_TYPE_FLAG
  764. };
  765.  
  766. /* End of code for Persistent objects */
  767. /* -------------------------------------------------------- */
  768.  
  769. /* List of methods defined in the module */
  770.  
  771. #ifdef DEBUG_LOG
  772. static PyObject *
  773. set_debug_log(PyObject *ignored, PyObject *args)
  774. {
  775.   Py_INCREF(args);
  776.   ASSIGN(debug_log, args);
  777.   if(debug_log) idebug_log=-1;
  778.   else idebug_log=0;
  779.   Py_INCREF(Py_None);
  780.   return Py_None;
  781. }
  782. #endif
  783.  
  784. static struct PyMethodDef cP_methods[] = {
  785. #ifdef DEBUG_LOG
  786.   {"set_debug_log", (PyCFunction)set_debug_log, METH_VARARGS,
  787.    "set_debug_log(callable) -- Provide a function to log events\n"
  788.    "\n"
  789.    "The function will be called with an event name and a persistent object.\n"
  790.   },
  791. #endif
  792.   {NULL,        NULL}        /* sentinel */
  793. };
  794.  
  795.  
  796. /* Initialization function for the module (*must* be called initcPersistence) */
  797.  
  798. typedef int (*intfunctionwithpythonarg)(PyObject*);
  799.  
  800. static cPersistenceCAPIstruct
  801. truecPersistenceCAPI = {
  802.   &(Pertype.methods),
  803.   (getattrofunc)Per_getattro,    /*tp_getattr with object key*/
  804.   (setattrofunc)Per_setattro,    /*tp_setattr with object key*/
  805.   changed,
  806.   (intfunctionwithpythonarg)Per_setstate,
  807.   (pergetattr)Per_getattr,
  808.   (persetattr)_setattro,
  809. };
  810.  
  811. void
  812. initcPersistence()
  813. {
  814.   PyObject *m, *d;
  815.   char *rev="$Revision: 1.38.10.1 $";
  816.  
  817.   TimeStamp=PyString_FromString("TimeStamp");
  818.   if (! TimeStamp) return;
  819.   ASSIGN(TimeStamp, PyImport_Import(TimeStamp));
  820.   if (! TimeStamp) return;
  821.   ASSIGN(TimeStamp, PyObject_GetAttrString(TimeStamp, "TimeStamp"));
  822.   if (! TimeStamp) return;
  823.   
  824.   m = Py_InitModule4("cPersistence", cP_methods,
  825.              "",
  826.              (PyObject*)NULL,PYTHON_API_VERSION);
  827.  
  828.   init_strings();
  829.  
  830.   d = PyModule_GetDict(m);
  831.   PyDict_SetItemString(d,"__version__",
  832.                PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
  833.   PyExtensionClass_Export(d, "Persistent",  Pertype);
  834.   PyExtensionClass_Export(d, "Overridable", Overridable);
  835.  
  836.   cPersistenceCAPI=&truecPersistenceCAPI;
  837.   PyDict_SetItemString(d, "CAPI",
  838.                PyCObject_FromVoidPtr(cPersistenceCAPI,NULL));
  839.  
  840.   if (PyErr_Occurred())
  841.     Py_FatalError("can't initialize module cDocumentTemplate");
  842. }
  843.